/**
 * HTML后处理工具
 * 对mammoth转换后的HTML进行进一步处理，使其符合编辑器节点要求
 */

/**
 * 处理图片节点
 * 将包裹在p标签中的图片提取出来，避免图片被段落包裹
 */
function processImages(doc: Document): void {
  for (const img of doc.querySelectorAll('img')) {
    const parent = img.parentElement
    if (parent?.tagName === 'P') {
      // 将图片移到段落前面
      parent.insertAdjacentElement('beforebegin', img)
      
      // 如果段落为空，删除段落
      if (!parent.hasChildNodes() && parent.textContent === '') {
        parent.remove()
      }
    }
  }
}

/**
 * 处理列表节点
 * 确保列表结构正确，添加必要的属性，处理任务列表
 */
function processLists(doc: Document): void {
  // 处理无序列表
  for (const ul of doc.querySelectorAll('ul')) {
    // 检查是否是任务列表（包含复选框的列表）
    const hasCheckbox = ul.querySelector('input[type="checkbox"]')
    if (hasCheckbox) {
      // 转换为任务列表
      ul.setAttribute('data-type', 'taskList')
      ul.classList.add('task-list')
      
      // 处理任务项
      for (const li of ul.querySelectorAll('li')) {
        const checkbox = li.querySelector('input[type="checkbox"]')
        if (checkbox) {
          li.setAttribute('data-type', 'taskItem')
          const isChecked = (checkbox as HTMLInputElement).checked
          li.setAttribute('data-checked', isChecked ? 'true' : 'false')
        }
      }
      continue
    }
    
    // 普通无序列表：确保ul有正确的类型属性
    const listType = ul.getAttribute('type') || 
                     ul.style.getPropertyValue('list-style-type') || 
                     'disc'
    if (!ul.hasAttribute('type')) {
      ul.setAttribute('type', listType)
    }
    if (!ul.style.getPropertyValue('list-style-type')) {
      ul.style.setProperty('list-style-type', listType)
    }
  }
  
  // 处理有序列表
  for (const ol of doc.querySelectorAll('ol')) {
    const listType = ol.style.getPropertyValue('list-style-type') || 'decimal'
    if (!ol.style.getPropertyValue('list-style-type')) {
      ol.style.setProperty('list-style-type', listType)
    }
    
    // 处理有序列表的type属性（如果style中有）
    if (listType && !ol.hasAttribute('type')) {
      // 将list-style-type值转换为type属性值
      const typeMap: Record<string, string> = {
        'decimal': 'decimal',
        'lower-alpha': 'lower-alpha',
        'upper-alpha': 'upper-alpha',
        'lower-roman': 'lower-roman',
        'upper-roman': 'upper-roman',
        'lower-latin': 'lower-alpha',
        'upper-latin': 'upper-alpha',
      }
      const typeValue = typeMap[listType] || 'decimal'
      ol.setAttribute('type', typeValue)
    }
  }
}

/**
 * 处理代码块节点
 * 确保代码块有正确的类名和结构
 */
function processCodeBlocks(doc: Document): void {
  for (const pre of doc.querySelectorAll('pre')) {
    // 确保有preCode类
    if (!pre.classList.contains('preCode')) {
      pre.classList.add('preCode')
    }
    
    // 如果pre中没有code标签，添加一个
    if (!pre.querySelector('code')) {
      const code = doc.createElement('code')
      // 将pre的内容移到code中
      while (pre.firstChild) {
        code.appendChild(pre.firstChild)
      }
      pre.appendChild(code)
    }
  }
}

/**
 * 处理表格节点
 * 确保表格结构完整，添加必要的tbody，处理单元格对齐、背景色等
 */
function processTables(doc: Document): void {
  for (const table of doc.querySelectorAll('table')) {
    // 如果表格没有tbody，但有tr，则创建tbody
    if (!table.querySelector('tbody') && table.querySelector('tr')) {
      const tbody = doc.createElement('tbody')
      const rows = Array.from(table.querySelectorAll(':scope > tr'))
      rows.forEach(row => {
        tbody.appendChild(row)
      })
      if (tbody.children.length > 0) {
        table.appendChild(tbody)
      }
    }
  }
  
  // 处理表格单元格对齐、背景色、文字颜色
  for (const cell of doc.querySelectorAll('td, th')) {
    const htmlCell = cell as HTMLElement
    const style = htmlCell.style
    
    // 处理单元格对齐（从style转换为align属性）
    const textAlign = style.getPropertyValue('text-align')?.trim() || 'left'
    const verticalAlign = style.getPropertyValue('vertical-align')?.trim() || 'middle'
    
    // 映射对齐方式
    const alignMap: Record<string, string> = {
      'left': 'left',
      'center': 'center',
      'right': 'right',
      'justify': 'justify',
      'start': 'left',
      'end': 'right',
    }
    
    const valignMap: Record<string, string> = {
      'top': 'top',
      'middle': 'middle',
      'center': 'middle',
      'bottom': 'bottom',
      'baseline': 'middle',
    }
    
    const horizontalAlign = alignMap[textAlign] || 'left'
    const verticalAlignValue = valignMap[verticalAlign] || 'middle'
    
    // 组合对齐方式（12种组合）
    const alignValue = `${horizontalAlign}-${verticalAlignValue}`
    if (alignValue !== 'left-middle') { // 默认值不需要设置
      cell.setAttribute('align', alignValue)
    }
    
    // 处理单元格背景色（从style转换为background属性）
    const bgColor = style.getPropertyValue('background-color')?.trim() || 
                    style.getPropertyValue('background')?.trim()
    if (bgColor && bgColor !== 'transparent' && bgColor !== 'rgba(0, 0, 0, 0)') {
      // 提取颜色值（可能是rgb、rgba、hex等格式）
      const colorMatch = bgColor.match(/^rgba?\(([^)]+)\)$/) || 
                        bgColor.match(/^#?([0-9a-fA-F]{3,8})$/) ||
                        bgColor.match(/^([a-zA-Z]+)$/)
      if (colorMatch) {
        cell.setAttribute('background', bgColor)
      }
    }
    
    // 处理单元格文字颜色（从style转换为color属性）
    const textColor = style.getPropertyValue('color')?.trim()
    if (textColor && textColor !== 'rgb(0, 0, 0)' && textColor !== '#000000') {
      cell.setAttribute('color', textColor)
    }
  }
}

/**
 * 处理引用节点
 * 确保blockquote有正确的类名
 */
function processBlockquotes(doc: Document): void {
  for (const blockquote of doc.querySelectorAll('blockquote')) {
    if (!blockquote.classList.contains('blockquote')) {
      blockquote.classList.add('blockquote')
    }
  }
}

/**
 * 从Word样式类名和样式属性推断节点类型
 * 处理Word可能生成的带有样式类名或样式属性的段落，转换为正确的HTML结构
 */
function processWordStyleClasses(doc: Document): void {
  // 第一步：处理明确有标题类名的段落
  for (const p of doc.querySelectorAll('p[class*="heading"], p[class*="Heading"], p[class*="标题"]')) {
    const htmlP = p as HTMLElement
    const className = htmlP.className.toLowerCase()
    
    // 尝试从类名推断标题级别
    let headingLevel = 0
    if (className.includes('heading1') || className.includes('标题1') || className.includes('title')) {
      headingLevel = 1
    } else if (className.includes('heading2') || className.includes('标题2') || className.includes('subtitle')) {
      headingLevel = 2
    } else if (className.includes('heading3') || className.includes('标题3')) {
      headingLevel = 3
    } else if (className.includes('heading4') || className.includes('标题4')) {
      headingLevel = 4
    } else if (className.includes('heading5') || className.includes('标题5')) {
      headingLevel = 5
    } else if (className.includes('heading6') || className.includes('标题6')) {
      headingLevel = 6
    }
    
    if (headingLevel > 0 && headingLevel <= 6) {
      const heading = doc.createElement(`h${headingLevel}`)
      heading.innerHTML = htmlP.innerHTML
      
      // 复制所有属性（除了class）
      Array.from(htmlP.attributes).forEach(attr => {
        if (attr.name !== 'class') {
          heading.setAttribute(attr.name, attr.value)
        }
      })
      
      // 保留样式（字体大小等）
      if (htmlP.style.cssText) {
        heading.style.cssText = htmlP.style.cssText
      }
      
      htmlP.replaceWith(heading)
    }
  }
  
  // 第二步：处理可能通过字体大小等样式特征识别的标题
  // 只处理没有在特定容器中的段落（避免误判列表、表格中的大字体文本）
  for (const p of doc.querySelectorAll('p')) {
    // 跳过已经在特定容器中的段落
    if (p.closest('ul, ol, table, blockquote')) continue
    
    const htmlP = p as HTMLElement
    const style = htmlP.style
    
    // 检查是否已经有标题特征（大字体 + 粗体）
    const fontSize = style.getPropertyValue('font-size') || style.fontSize
    const fontWeight = style.getPropertyValue('font-weight') || style.fontWeight
    
    if (fontSize) {
      const sizeMatch = fontSize.match(/^([\d.]+)(px|em|pt)$/i)
      if (sizeMatch) {
        const sizeValue = parseFloat(sizeMatch[1])
        const unit = sizeMatch[2].toLowerCase()
        
        // 转换为px进行判断
        let sizeInPx = sizeValue
        if (unit === 'em') {
          sizeInPx = sizeValue * 16 // 假设基础字号16px
        } else if (unit === 'pt') {
          sizeInPx = sizeValue * 1.33
        }
        
        // 标题通常有较大的字体（>= 18px）并且可能是粗体
        // 但要避免误判，需要更严格的判断
        const isBold = fontWeight && (fontWeight === 'bold' || parseInt(fontWeight) >= 600)
        const isLargeFont = sizeInPx >= 18
        
        if (isLargeFont && isBold) {
          let headingLevel = 0
          // 根据字体大小推断标题级别
          if (sizeInPx >= 28) headingLevel = 1
          else if (sizeInPx >= 24) headingLevel = 2
          else if (sizeInPx >= 20) headingLevel = 3
          else if (sizeInPx >= 18) headingLevel = 4
          
          if (headingLevel > 0 && headingLevel <= 6) {
            const heading = doc.createElement(`h${headingLevel}`)
            heading.innerHTML = htmlP.innerHTML
            
            // 复制所有属性
            Array.from(htmlP.attributes).forEach(attr => {
              heading.setAttribute(attr.name, attr.value)
            })
            
            // 保留样式
            if (htmlP.style.cssText) {
              heading.style.cssText = htmlP.style.cssText
            }
            
            htmlP.replaceWith(heading)
          }
        }
      }
    }
  }
  
  // 处理Word可能生成的引用样式类名
  // 也检查是否有缩进、左边框等引用特征样式
  for (const p of doc.querySelectorAll('p[class*="blockquote"], p[class*="引用"], p[style*="margin-left"], p[style*="padding-left"], p[style*="border-left"]')) {
    const htmlP = p as HTMLElement
    const className = htmlP.className.toLowerCase()
    const style = htmlP.style
    
    // 检查是否真的是引用（通过类名或样式特征）
    const isBlockquote = className.includes('blockquote') || 
                        className.includes('引用') ||
                        (style.getPropertyValue('margin-left') && parseFloat(style.getPropertyValue('margin-left')) > 20) ||
                        (style.getPropertyValue('padding-left') && parseFloat(style.getPropertyValue('padding-left')) > 20) ||
                        style.getPropertyValue('border-left')
    
    if (isBlockquote) {
      const blockquote = doc.createElement('blockquote')
      blockquote.className = 'blockquote'
      blockquote.innerHTML = htmlP.innerHTML
      
      // 复制样式（除了可能导致问题的样式）
      Array.from(htmlP.attributes).forEach(attr => {
        if (attr.name !== 'class') {
          blockquote.setAttribute(attr.name, attr.value)
        }
      })
      
      // 保留样式，但移除左边距（引用块有自己的样式）
      if (htmlP.style.cssText) {
        blockquote.style.cssText = htmlP.style.cssText
        blockquote.style.removeProperty('margin-left')
        blockquote.style.removeProperty('padding-left')
      }
      
      htmlP.replaceWith(blockquote)
    }
  }
  
  // 处理Word可能生成的代码块样式类名
  // 也检查是否有等宽字体样式
  for (const p of doc.querySelectorAll('p[class*="code"], p[class*="代码"], p[style*="font-family"]')) {
    const htmlP = p as HTMLElement
    const className = htmlP.className.toLowerCase()
    const fontFamily = htmlP.style.getPropertyValue('font-family') || htmlP.style.fontFamily
    
    // 检查是否是代码块（通过类名或等宽字体）
    const isCodeBlock = className.includes('code') || 
                       className.includes('代码') ||
                       (fontFamily && /monospace|courier|consolas|fixedsys|等宽|mono/i.test(fontFamily))
    
    if (isCodeBlock) {
      const pre = doc.createElement('pre')
      pre.className = 'preCode'
      const code = doc.createElement('code')
      code.innerHTML = htmlP.innerHTML
      pre.appendChild(code)
      
      // 保留样式
      if (htmlP.style.cssText) {
        pre.style.cssText = htmlP.style.cssText
      }
      
      htmlP.replaceWith(pre)
    }
  }
}

/**
 * 处理标题节点
 * 确保标题有正确的层级（h1-h6），处理缩进
 */
function processHeadings(doc: Document): void {
  for (const heading of doc.querySelectorAll('h1, h2, h3, h4, h5, h6')) {
    // 确保标题标签正确（编辑器支持h1-h6）
    const level = parseInt(heading.tagName.charAt(1))
    if (isNaN(level) || level < 1 || level > 6) {
      // 如果标题级别不正确，转换为h1
      const h1 = doc.createElement('h1')
      h1.innerHTML = heading.innerHTML
      heading.replaceWith(h1)
    }
    
    // 处理缩进（从text-indent转换为indent类）
    const htmlHeading = heading as HTMLElement
    const textIndent = htmlHeading.style.getPropertyValue('text-indent')
    if (textIndent) {
      // 解析缩进值（通常是em或px单位）
      const indentMatch = textIndent.match(/^([\d.]+)(em|px)$/)
      if (indentMatch) {
        const indentValue = parseFloat(indentMatch[1])
        const unit = indentMatch[2]
        
        // 转换为缩进级别（0-5）
        // 2em = indent-1, 4em = indent-2, 以此类推
        let indentLevel = 0
        if (unit === 'em') {
          indentLevel = Math.min(5, Math.floor(indentValue / 2))
        } else if (unit === 'px') {
          // 假设基础字号14px，2em = 28px
          indentLevel = Math.min(5, Math.floor(indentValue / 28))
        }
        
        if (indentLevel > 0) {
          heading.classList.add(`indent-${indentLevel}`)
        }
      }
    }
  }
}

/**
 * 处理文本样式节点
 * 确保文本样式标记正确，处理链接类名，处理从Word导入的样式
 * 根据映射文档处理所有文本样式：bold, italic, underline, strike, mark, sup, sub, code等
 */
function processTextStyles(doc: Document): void {
  // 1. 处理高亮标记（mark标签）
  for (const mark of doc.querySelectorAll('mark')) {
    // 确保mark标签有正确的样式属性
    const bgColor = mark.getAttribute('data-color') || 
                    mark.style.backgroundColor ||
                    mark.style.getPropertyValue('background-color')
    if (bgColor && !mark.getAttribute('data-color')) {
      // 提取颜色值（去掉rgb/rgba包装）
      let colorValue = bgColor
      if (bgColor.startsWith('rgb') || bgColor.startsWith('rgba')) {
        // 尝试从rgb/rgba中提取颜色值
        const match = bgColor.match(/rgba?\(([^)]+)\)/)
        if (match) {
          const parts = match[1].split(',').map(p => p.trim())
          if (parts.length >= 3) {
            // 转换为十六进制
            const r = parseInt(parts[0]).toString(16).padStart(2, '0')
            const g = parseInt(parts[1]).toString(16).padStart(2, '0')
            const b = parseInt(parts[2]).toString(16).padStart(2, '0')
            colorValue = `#${r}${g}${b}`
          }
        }
      } else if (!bgColor.startsWith('#')) {
        colorValue = `#${bgColor}`
      }
      mark.setAttribute('data-color', colorValue)
    }
  }
  
  // 2. 处理从Word导入的背景色（高亮）样式
  // Word中的背景色可能以span的style属性形式存在
  for (const span of doc.querySelectorAll('span[style*="background"]')) {
    const htmlSpan = span as HTMLElement
    const bgColor = htmlSpan.style.getPropertyValue('background-color') || 
                    htmlSpan.style.getPropertyValue('background')
    if (bgColor && bgColor !== 'transparent' && bgColor !== 'rgba(0, 0, 0, 0)') {
      // 转换为mark标签
      const mark = doc.createElement('mark')
      
      // 提取颜色值
      let colorValue = bgColor
      if (bgColor.startsWith('rgb') || bgColor.startsWith('rgba')) {
        const match = bgColor.match(/rgba?\(([^)]+)\)/)
        if (match) {
          const parts = match[1].split(',').map(p => p.trim())
          if (parts.length >= 3) {
            const r = parseInt(parts[0]).toString(16).padStart(2, '0')
            const g = parseInt(parts[1]).toString(16).padStart(2, '0')
            const b = parseInt(parts[2]).toString(16).padStart(2, '0')
            colorValue = `#${r}${g}${b}`
          }
        }
      } else if (!bgColor.startsWith('#')) {
        colorValue = `#${bgColor}`
      }
      
      mark.setAttribute('data-color', colorValue)
      mark.style.setProperty('background-color', bgColor)
      mark.style.setProperty('color', 'inherit')
      
      // 将span的内容移到mark中
      while (htmlSpan.firstChild) {
        mark.appendChild(htmlSpan.firstChild)
      }
      htmlSpan.replaceWith(mark)
    }
  }
  
  // 3. 处理下划线（u标签）
  // Word中的下划线可能以text-decoration: underline形式存在
  const underlineSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="text-decoration"]')) {
    const htmlSpan = span as HTMLElement
    const textDecoration = htmlSpan.style.getPropertyValue('text-decoration') || 
                          htmlSpan.style.textDecoration
    if (textDecoration && textDecoration.includes('underline')) {
      // 检查是否已经有u标签包裹
      if (htmlSpan.tagName !== 'U' && !htmlSpan.closest('u')) {
        underlineSpans.push(htmlSpan)
      }
    }
  }
  
  for (const htmlSpan of underlineSpans) {
    const u = doc.createElement('u')
    u.style.setProperty('text-decoration', 'underline')
    while (htmlSpan.firstChild) {
      u.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(u)
  }
  
  // 4. 处理删除线（s/del标签）
  // Word中的删除线可能以text-decoration: line-through形式存在
  const strikethroughSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="text-decoration"]')) {
    const htmlSpan = span as HTMLElement
    const textDecoration = htmlSpan.style.getPropertyValue('text-decoration') || 
                          htmlSpan.style.textDecoration
    if (textDecoration && textDecoration.includes('line-through')) {
      // 检查是否已经有s或del标签包裹
      if (htmlSpan.tagName !== 'S' && htmlSpan.tagName !== 'DEL' && 
          !htmlSpan.closest('s, del')) {
        strikethroughSpans.push(htmlSpan)
      }
    }
  }
  
  for (const htmlSpan of strikethroughSpans) {
    const s = doc.createElement('s')
    s.style.setProperty('text-decoration', 'line-through')
    while (htmlSpan.firstChild) {
      s.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(s)
  }
  
  // 5. 处理上标（sup标签）
  // Word中的上标可能以vertical-align: super形式存在
  const supSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="vertical-align"]')) {
    const htmlSpan = span as HTMLElement
    const verticalAlign = htmlSpan.style.getPropertyValue('vertical-align') || 
                          htmlSpan.style.verticalAlign
    if (verticalAlign && verticalAlign === 'super') {
      if (htmlSpan.tagName !== 'SUP' && !htmlSpan.closest('sup')) {
        supSpans.push(htmlSpan)
      }
    }
  }
  
  for (const htmlSpan of supSpans) {
    const sup = doc.createElement('sup')
    sup.style.setProperty('vertical-align', 'super')
    while (htmlSpan.firstChild) {
      sup.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(sup)
  }
  
  // 6. 处理下标（sub标签）
  // Word中的下标可能以vertical-align: sub形式存在
  const subSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="vertical-align"]')) {
    const htmlSpan = span as HTMLElement
    const verticalAlign = htmlSpan.style.getPropertyValue('vertical-align') || 
                          htmlSpan.style.verticalAlign
    if (verticalAlign && verticalAlign === 'sub') {
      if (htmlSpan.tagName !== 'SUB' && !htmlSpan.closest('sub')) {
        subSpans.push(htmlSpan)
      }
    }
  }
  
  for (const htmlSpan of subSpans) {
    const sub = doc.createElement('sub')
    sub.style.setProperty('vertical-align', 'sub')
    while (htmlSpan.firstChild) {
      sub.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(sub)
  }
  
  // 7. 处理粗体（strong/b标签）
  // Word中的粗体可能以font-weight: bold形式存在
  const boldSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="font-weight"]')) {
    const htmlSpan = span as HTMLElement
    const fontWeight = htmlSpan.style.getPropertyValue('font-weight') || 
                      htmlSpan.style.fontWeight
    if (fontWeight && (fontWeight === 'bold' || parseInt(fontWeight) >= 600)) {
      if (htmlSpan.tagName !== 'STRONG' && htmlSpan.tagName !== 'B' && 
          !htmlSpan.closest('strong, b')) {
        boldSpans.push(htmlSpan)
      }
    }
  }
  
  for (const htmlSpan of boldSpans) {
    const strong = doc.createElement('strong')
    while (htmlSpan.firstChild) {
      strong.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(strong)
  }
  
  // 8. 处理斜体（em/i标签）
  // Word中的斜体可能以font-style: italic形式存在
  const italicSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="font-style"]')) {
    const htmlSpan = span as HTMLElement
    const fontStyle = htmlSpan.style.getPropertyValue('font-style') || 
                     htmlSpan.style.fontStyle
    if (fontStyle && fontStyle === 'italic') {
      if (htmlSpan.tagName !== 'EM' && htmlSpan.tagName !== 'I' && 
          !htmlSpan.closest('em, i')) {
        italicSpans.push(htmlSpan)
      }
    }
  }
  
  for (const htmlSpan of italicSpans) {
    const em = doc.createElement('em')
    while (htmlSpan.firstChild) {
      em.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(em)
  }
  
  // 9. 处理行内代码（code标签）
  // Word中的等宽字体可能以font-family: monospace形式存在
  const codeSpans: HTMLElement[] = []
  for (const span of doc.querySelectorAll('span[style*="font-family"]')) {
    const htmlSpan = span as HTMLElement
    const fontFamily = htmlSpan.style.getPropertyValue('font-family') || 
                      htmlSpan.style.fontFamily
    // 检查是否是等宽字体，且不在代码块中
    if (fontFamily && /monospace|courier|consolas|fixedsys|等宽|mono/i.test(fontFamily) &&
        htmlSpan.tagName !== 'CODE' && !htmlSpan.closest('code, pre')) {
      codeSpans.push(htmlSpan)
    }
  }
  
  for (const htmlSpan of codeSpans) {
    const code = doc.createElement('code')
    code.style.setProperty('font-family', 'monospace')
    while (htmlSpan.firstChild) {
      code.appendChild(htmlSpan.firstChild)
    }
    htmlSpan.replaceWith(code)
  }
  
  // 10. 处理链接类名
  for (const link of doc.querySelectorAll('a[href]')) {
    // 确保链接有默认的样式类名
    if (!link.classList.contains('text-blue-500')) {
      link.classList.add('text-blue-500')
    }
    if (!link.classList.contains('underline')) {
      link.classList.add('underline')
    }
  }
  
  // 11. 确保已有的strong/b, em/i, u, s/del标签正确
  // 将b标签转换为strong，将i标签转换为em
  for (const b of doc.querySelectorAll('b')) {
    const strong = doc.createElement('strong')
    strong.innerHTML = b.innerHTML
    Array.from(b.attributes).forEach(attr => {
      strong.setAttribute(attr.name, attr.value)
    })
    b.replaceWith(strong)
  }
  
  for (const i of doc.querySelectorAll('i')) {
    const em = doc.createElement('em')
    em.innerHTML = i.innerHTML
    Array.from(i.attributes).forEach(attr => {
      em.setAttribute(attr.name, attr.value)
    })
    i.replaceWith(em)
  }
  
  // 将strike标签转换为s
  for (const strike of doc.querySelectorAll('strike')) {
    const s = doc.createElement('s')
    s.innerHTML = strike.innerHTML
    Array.from(strike.attributes).forEach(attr => {
      s.setAttribute(attr.name, attr.value)
    })
    strike.replaceWith(s)
  }
}

/**
 * 处理段落和文本对齐、缩进
 * 处理段落的对齐方式（包括分散对齐）和缩进
 */
function processParagraphAlignmentAndIndent(doc: Document): void {
  // 处理段落对齐和缩进
  for (const p of doc.querySelectorAll('p, h1, h2, h3, h4, h5, h6')) {
    const htmlP = p as HTMLElement
    const style = htmlP.style
    
    // 处理文本对齐（包括分散对齐）
    const textAlign = style.getPropertyValue('text-align')?.trim()
    const textAlignLast = style.getPropertyValue('text-align-last')?.trim()
    
    if (textAlign === 'justify' && textAlignLast === 'justify') {
      // 分散对齐
      style.setProperty('text-align-last', 'justify')
    }
    
    // 处理缩进（从text-indent转换为indent类）
    const textIndent = style.getPropertyValue('text-indent')
    if (textIndent) {
      // 解析缩进值（通常是em或px单位）
      const indentMatch = textIndent.match(/^([\d.]+)(em|px)$/)
      if (indentMatch) {
        const indentValue = parseFloat(indentMatch[1])
        const unit = indentMatch[2]
        
        // 转换为缩进级别（0-5）
        // 2em = indent-1, 4em = indent-2, 以此类推
        let indentLevel = 0
        if (unit === 'em') {
          indentLevel = Math.min(5, Math.floor(indentValue / 2))
        } else if (unit === 'px') {
          // 假设基础字号14px，2em = 28px
          indentLevel = Math.min(5, Math.floor(indentValue / 28))
        }
        
        if (indentLevel > 0) {
          p.classList.add(`indent-${indentLevel}`)
        }
      }
    }
  }
}

/**
 * 处理特殊字符
 * 将非断空格转换为普通空格
 */
function processSpecialCharacters(doc: Document): void {
  // 遍历所有文本节点
  const walker = doc.createTreeWalker(
    doc.body,
    NodeFilter.SHOW_TEXT,
    null
  )
  
  const textNodes: Text[] = []
  let node: Node | null
  while ((node = walker.nextNode())) {
    if (node.nodeType === Node.TEXT_NODE) {
      textNodes.push(node as Text)
    }
  }
  
  textNodes.forEach(textNode => {
    // 替换非断空格为普通空格
    if (textNode.nodeValue) {
      textNode.nodeValue = textNode.nodeValue.replace(/\u00A0/g, ' ')
    }
  })
}

/**
 * 处理分页符
 * 识别并统一分页符的表示方式
 */
function processPageBreaks(doc: Document): void {
  // 处理多种分页符表示方式
  // 1. div[data-type="page-break"] - 确保为空且包含正确的类名
  for (const div of doc.querySelectorAll('div[data-type="page-break"]')) {
    if (!div.classList.contains('page-break')) {
      div.classList.add('page-break')
    }
    // 确保分页符为空（移除所有内容）
    const htmlDiv = div as HTMLElement
    htmlDiv.innerHTML = ''
  }
  
  // 2. hr.page-break
  for (const hr of doc.querySelectorAll('hr.page-break')) {
    const div = doc.createElement('div')
    div.setAttribute('data-type', 'page-break')
    div.className = 'page-break'
    hr.replaceWith(div)
  }
  
  // 3. p.page-break 或包含换页符字符的段落
  for (const p of doc.querySelectorAll('p.page-break, p')) {
    if (p.classList.contains('page-break') || 
        p.textContent?.includes('\f') || 
        p.textContent?.includes('\u000C')) {
      const div = doc.createElement('div')
      div.setAttribute('data-type', 'page-break')
      div.className = 'page-break'
      p.replaceWith(div)
    }
  }
}

/**
 * 处理Word目录（Table of Contents）
 * 识别Word中的目录并转换为编辑器的TOC节点
 * 
 * Word目录的结构特征：
 * - 连续的段落（<p>标签）
 * - 每个段落包含一个超链接（<a>标签）
 * - 链接的href属性以 #_Toc 开头（Word自动生成的目录锚点）
 * - 至少连续2个这样的段落才认为是目录
 * 
 * 示例：
 * <p><a href="#_Toc5kwost">标题 页码</a></p>
 * <p><a href="#_Tocou2pwm">标题 页码</a></p>
 */
function processTableOfContents(doc: Document): void {
  // 先处理通过mammoth特定标记转换的目录（类名或属性包含TOC相关标记）
  const tocMarkers = doc.querySelectorAll('[class*="toc" i], [class*="TOC"], [data-toc]')
  for (const marker of Array.from(tocMarkers)) {
    const htmlMarker = marker as HTMLElement
    // 如果已经是TOC节点，跳过
    if (htmlMarker.getAttribute('data-type') === 'toc') {
      continue
    }
    
    // 检查是否包含目录特征（包含 #_Toc 链接）
    const hasTocLink = htmlMarker.querySelector('a[href^="#_Toc"]')
    
    if (hasTocLink) {
      // 转换为TOC节点
      const tocDiv = doc.createElement('div')
      tocDiv.setAttribute('data-type', 'toc')
      tocDiv.setAttribute('data-toc-id', `toc-${Date.now()}-marker`)
      
      if (htmlMarker.parentElement) {
        htmlMarker.parentElement.insertBefore(tocDiv, htmlMarker)
        htmlMarker.remove()
      }
    }
  }
  
  // 基于结构特征识别目录：查找连续的包含 #_Toc 链接的段落
  // 使用单次遍历，提高效率
  const allElements = Array.from(doc.body.children) as HTMLElement[]
  const elementsToReplace: HTMLElement[] = []
  let tocStartIndex = -1
  
  // 单次遍历，识别连续的目录段落
  for (let i = 0; i < allElements.length; i++) {
    const element = allElements[i]
    const tagName = element.tagName.toLowerCase()
    
    // 只处理段落标签
    if (tagName !== 'p') {
      // 如果之前找到了目录段落，现在遇到非段落元素，目录结束
      if (tocStartIndex >= 0) {
        if (elementsToReplace.length >= 2) {
          // 找到了有效的目录，进行替换
          replaceTocElements(elementsToReplace, doc)
        }
        // 重置状态，继续查找下一个可能的目录
        elementsToReplace.length = 0
        tocStartIndex = -1
      }
      continue
    }
    
    // 检查段落是否包含 #_Toc 链接
    // 先检查第一个子元素是否是链接（最常见情况，性能更好）
    const firstLink = element.firstElementChild as HTMLAnchorElement
    let tocLink: HTMLAnchorElement | null = null
    
    if (firstLink && 
        firstLink.tagName === 'A' && 
        firstLink.getAttribute('href')?.startsWith('#_Toc')) {
      tocLink = firstLink
    } else {
      // 如果第一个子元素不是 #_Toc 链接，再查找整个段落
      tocLink = element.querySelector('a[href^="#_Toc"]')
    }
    
    if (tocLink) {
      // 找到了目录项
      if (tocStartIndex === -1) {
        // 记录目录开始位置
        tocStartIndex = i
      }
      // 添加到替换列表
      elementsToReplace.push(element)
    } else {
      // 没有找到目录链接
      if (tocStartIndex >= 0) {
        // 之前找到了目录段落，现在遇到非目录段落
        if (elementsToReplace.length >= 2) {
          // 至少有2个目录项，进行替换
          replaceTocElements(elementsToReplace, doc)
        }
        // 重置状态
        elementsToReplace.length = 0
        tocStartIndex = -1
      }
    }
  }
  
  // 处理文档末尾的目录（如果存在）
  if (tocStartIndex >= 0 && elementsToReplace.length >= 2) {
    replaceTocElements(elementsToReplace, doc)
  }
  
  /**
   * 将目录元素替换为TOC节点
   */
  function replaceTocElements(elements: HTMLElement[], document: Document): void {
    if (elements.length === 0) return
    
    // 创建TOC节点
    const tocDiv = document.createElement('div')
    tocDiv.setAttribute('data-type', 'toc')
    tocDiv.setAttribute('data-toc-id', `toc-${Date.now()}`)
    
    // 在第一个元素的位置插入TOC节点
    const firstElement = elements[0]
    if (firstElement.parentElement) {
      firstElement.parentElement.insertBefore(tocDiv, firstElement)
      
      // 移除所有目录相关的元素
      elements.forEach(el => {
        if (el.parentElement) {
          el.parentElement.removeChild(el)
        }
      })
    }
  }
}

/**
 * 清理空段落
 * 删除只包含空白字符的段落（但保留必要的结构）
 */
function removeEmptyParagraphs(doc: Document): void {
  // 收集需要删除的段落
  const paragraphsToRemove: HTMLElement[] = []
  
  for (const p of doc.querySelectorAll('p')) {
    // 跳过在blockquote中的段落
    if (p.closest('blockquote')) continue
    // 跳过在列表中的段落
    if (p.closest('ul, ol')) continue
    // 跳过在表格中的段落
    if (p.closest('table')) continue
    
    // 检查是否为空
    const hasContent = p.textContent?.trim() || p.querySelector('img')
    if (!hasContent && p.children.length === 0) {
      // 如果段落是空的，但不是body的唯一子元素，可以删除
      const parent = p.parentElement
      if (parent && parent.children.length > 1) {
        paragraphsToRemove.push(p)
      }
    }
  }
  
  // 删除收集到的空段落
  paragraphsToRemove.forEach(p => p.remove())
}

/**
 * 验证和修复节点结构
 * 确保节点嵌套符合 Tiptap schema 要求
 */
function validateNodeStructure(doc: Document): void {
  // 确保任务列表结构正确
  for (const ul of doc.querySelectorAll('ul[data-type="taskList"]')) {
    // 任务列表必须包含 taskItem
    for (const li of ul.querySelectorAll('li')) {
      if (!li.hasAttribute('data-type')) {
        li.setAttribute('data-type', 'taskItem')
      }
      if (!li.hasAttribute('data-checked')) {
        // 检查是否有选中的复选框
        const checkbox = li.querySelector('input[type="checkbox"]')
        const isChecked = checkbox ? (checkbox as HTMLInputElement).checked : false
        li.setAttribute('data-checked', isChecked ? 'true' : 'false')
      }
      // 确保任务项包含 label 结构（Tiptap 任务列表的要求）
      const htmlLi = li as HTMLElement
      if (!htmlLi.querySelector('label')) {
        const checkbox = htmlLi.querySelector('input[type="checkbox"]')
        const label = doc.createElement('label')
        
        // 收集所有内容节点
        const allNodes: Node[] = []
        while (htmlLi.firstChild) {
          allNodes.push(htmlLi.firstChild)
          htmlLi.removeChild(htmlLi.firstChild)
        }
        
        // 将复选框添加到label
        if (checkbox) {
          label.appendChild(checkbox)
        }
        
        // 将其他内容包装在span中
        const span = doc.createElement('span')
        allNodes.forEach(node => {
          if (node !== checkbox) {
            span.appendChild(node)
          }
        })
        
        if (span.textContent?.trim() || checkbox) {
          if (span.textContent?.trim()) {
            label.appendChild(span)
          }
          htmlLi.appendChild(label)
        } else {
          // 如果没有内容，恢复原始节点
          allNodes.forEach(node => htmlLi.appendChild(node))
        }
      }
    }
  }
  
  // 确保列表项内不能直接包含块级元素（除了嵌套列表）
  for (const li of doc.querySelectorAll('li')) {
    const children = Array.from(li.children)
    for (const child of children) {
      const tagName = child.tagName.toLowerCase()
      // 如果li包含块级元素（除了ul/ol），需要包装在段落中
      if (['p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'table'].includes(tagName) && 
          !['ul', 'ol'].includes(tagName)) {
        // 如果还没有包装在段落中，创建一个段落
        if (tagName !== 'p') {
          const p = doc.createElement('p')
          child.parentNode?.insertBefore(p, child)
          p.appendChild(child)
        }
      }
    }
  }
  
  // 确保表格结构完整
  for (const table of doc.querySelectorAll('table')) {
    // 确保表格有tbody
    if (!table.querySelector('tbody')) {
      const tbody = doc.createElement('tbody')
      const rows = Array.from(table.querySelectorAll(':scope > tr'))
      if (rows.length > 0) {
        rows.forEach(row => tbody.appendChild(row))
        table.appendChild(tbody)
      }
    }
    
    // 确保表格单元格内有内容（至少是段落）
    for (const cell of table.querySelectorAll('td, th')) {
      const htmlCell = cell as HTMLElement
      // 如果单元格为空或只包含文本节点，包装在段落中
      if (!htmlCell.querySelector('p') && htmlCell.textContent?.trim()) {
        const p = doc.createElement('p')
        while (htmlCell.firstChild) {
          p.appendChild(htmlCell.firstChild)
        }
        htmlCell.appendChild(p)
      }
    }
  }
  
  // 确保blockquote内包含段落
  for (const blockquote of doc.querySelectorAll('blockquote')) {
    const htmlBlockquote = blockquote as HTMLElement
    if (!htmlBlockquote.querySelector('p') && htmlBlockquote.textContent?.trim()) {
      const p = doc.createElement('p')
      while (htmlBlockquote.firstChild) {
        p.appendChild(htmlBlockquote.firstChild)
      }
      htmlBlockquote.appendChild(p)
    }
  }
  
  // 确保pre内有code标签
  for (const pre of doc.querySelectorAll('pre')) {
    if (!pre.querySelector('code')) {
      const code = doc.createElement('code')
      while (pre.firstChild) {
        code.appendChild(pre.firstChild)
      }
      pre.appendChild(code)
    }
  }
  
  // 确保批注标记（Comment）结构正确
  for (const span of doc.querySelectorAll('span[data-comment-id]')) {
    const htmlSpan = span as HTMLElement
    // 确保有comment-mark类名
    if (!htmlSpan.classList.contains('comment-mark')) {
      htmlSpan.classList.add('comment-mark')
    }
    // 确保批注标记是内联的，不能包含块级元素
    const blockElements = htmlSpan.querySelectorAll('p, div, h1, h2, h3, h4, h5, h6, ul, ol, blockquote, pre, table, hr')
    if (blockElements.length > 0) {
      // 如果包含块级元素，移除批注标记，只保留内容
      const fragment = doc.createDocumentFragment()
      while (htmlSpan.firstChild) {
        fragment.appendChild(htmlSpan.firstChild)
      }
      htmlSpan.replaceWith(fragment)
    }
  }
  
  // 确保目录节点（Toc）结构正确
  for (const tocDiv of doc.querySelectorAll('div[data-type="toc"]')) {
    // 目录节点应该只包含必要的属性
    const tocId = tocDiv.getAttribute('data-toc-id')
    if (!tocId) {
      // 如果没有ID，生成一个
      tocDiv.setAttribute('data-toc-id', `toc-${Date.now()}`)
    }
    // 清理目录节点内的内容，因为目录是原子节点，内容由组件生成
    const htmlToc = tocDiv as HTMLElement
    htmlToc.innerHTML = ''
  }
}

/**
 * 清理不支持的HTML标签和属性
 * 移除或转换编辑器不支持的标签和属性，避免解析错误
 */
function sanitizeHtml(doc: Document): void {
  // 支持的块级标签
  const supportedBlockTags = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'hr', 'div', 'img']
  
  // 支持的内联标签
  const supportedInlineTags = ['strong', 'b', 'em', 'i', 'u', 's', 'del', 'mark', 'code', 'a', 'sub', 'sup', 'br', 'span']
  
  // 需要转换的标签映射
  const tagReplacements: Record<string, string> = {
    'b': 'strong',
    'i': 'em',
    'del': 's',
    'strike': 's',
  }
  
  // 允许的属性映射
  const allowedAttributes: Record<string, string[]> = {
    'a': ['href', 'target', 'rel', 'class'],
    'img': ['src', 'alt', 'width', 'height', 'style', 'class'],
    'table': ['style', 'class'],
    'td': ['colspan', 'rowspan', 'align', 'background', 'color', 'style', 'class'],
    'th': ['colspan', 'rowspan', 'align', 'background', 'color', 'style', 'class'],
    'ul': ['data-type', 'type', 'style', 'class'],
    'ol': ['type', 'style', 'start', 'class'],
    'li': ['data-type', 'data-checked', 'style', 'class'],
    'mark': ['data-color', 'style', 'class'],
    'span': ['data-comment-id', 'data-author-id', 'data-resolved', 'style', 'class'],
    'p': ['style', 'class'],
    'h1': ['style', 'class'],
    'h2': ['style', 'class'],
    'h3': ['style', 'class'],
    'h4': ['style', 'class'],
    'h5': ['style', 'class'],
    'h6': ['style', 'class'],
    'blockquote': ['class', 'style'],
    'pre': ['class', 'style'],
    'code': ['class', 'style'],
    'div': ['data-type', 'data-page-type', 'data-toc-id', 'class', 'style'],
    'hr': ['class', 'style'],
    'tr': ['style', 'class'],
    'thead': ['style', 'class'],
    'tbody': ['style', 'class'],
    'tfoot': ['style', 'class'],
  }
  
  // 需要保留的class名称（包括缩进类名）
  const allowedClasses = [
    'blockquote', 
    'preCode', 
    'page-break', 
    'text-blue-500', 
    'underline',
    'comment-mark',
    'indent-1',
    'indent-2',
    'indent-3',
    'indent-4',
    'indent-5',
    'task-list',
  ]
  
  // 收集所有需要处理的元素（从后往前处理，避免迭代问题）
  const allElements = Array.from(doc.querySelectorAll('*')).reverse()
  
  allElements.forEach(element => {
    if (element === doc.body || element === doc.documentElement) return
    
    const tagName = element.tagName.toLowerCase()
    
    // 处理标签替换
    if (tagReplacements[tagName]) {
      const newTag = tagReplacements[tagName]
      const newElement = doc.createElement(newTag)
      
      // 复制允许的属性
      const allowed = allowedAttributes[newTag] || []
      Array.from(element.attributes).forEach(attr => {
        if (allowed.includes(attr.name)) {
          newElement.setAttribute(attr.name, attr.value)
        }
      })
      newElement.innerHTML = element.innerHTML
      
      if (element.parentElement) {
        element.parentElement.replaceChild(newElement, element)
      }
      return
    }
    
    // 处理不支持的标签
    if (!supportedBlockTags.includes(tagName) && !supportedInlineTags.includes(tagName)) {
      // 如果是块级容器元素，转换为段落
      if (['div', 'section', 'article', 'header', 'footer', 'nav', 'aside', 'main'].includes(tagName)) {
        // 检查是否有data-type属性（用于分页符、目录等）
        const dataType = element.getAttribute('data-type')
        if (dataType === 'page-break') {
          // 保留div但清理属性，确保为空
          const div = doc.createElement('div')
          div.setAttribute('data-type', 'page-break')
          div.className = 'page-break'
          // 分页符应该是空的
          if (element.parentElement) {
            element.parentElement.replaceChild(div, element)
          }
        } else if (dataType === 'toc') {
          // 保留目录节点
          const div = doc.createElement('div')
          div.setAttribute('data-type', 'toc')
          const tocId = element.getAttribute('data-toc-id')
          if (tocId) {
            div.setAttribute('data-toc-id', tocId)
          }
          div.innerHTML = element.innerHTML
          if (element.parentElement) {
            element.parentElement.replaceChild(div, element)
          }
        } else {
          // 其他div转换为段落
          const p = doc.createElement('p')
          p.innerHTML = element.innerHTML
          if (element.parentElement) {
            element.parentElement.replaceChild(p, element)
          }
        }
      } else {
        // 其他不支持的标签，移除标签保留内容
        const fragment = doc.createDocumentFragment()
        while (element.firstChild) {
          fragment.appendChild(element.firstChild)
        }
        if (element.parentElement) {
          element.parentElement.replaceChild(fragment, element)
        }
      }
      return
    }
    
    // 对于支持的标签，也要确保没有无效的属性组合
    // 例如：某些属性组合可能导致 Tiptap 无法解析
    if (supportedBlockTags.includes(tagName) || supportedInlineTags.includes(tagName)) {
      // 移除所有 data-* 属性（除了明确允许的）
      const allowedDataAttributes = ['data-type', 'data-page-type', 'data-toc-id', 'data-comment-id', 'data-author-id', 'data-resolved', 'data-checked', 'data-color']
      Array.from(element.attributes).forEach(attr => {
        if (attr.name.startsWith('data-') && !allowedDataAttributes.includes(attr.name)) {
          element.removeAttribute(attr.name)
        }
      })
    }
    
    // 清理不支持的属性
    const allowed = allowedAttributes[tagName] || []
    const attrsToRemove: string[] = []
    
    Array.from(element.attributes).forEach(attr => {
      if (!allowed.includes(attr.name)) {
        attrsToRemove.push(attr.name)
      } else if (attr.name === 'class') {
        // 清理class属性，只保留允许的类名
        const classes = attr.value.split(' ').filter((cls: string) => {
          return allowedClasses.includes(cls.trim())
        })
        if (classes.length > 0) {
          element.setAttribute('class', classes.join(' '))
        } else {
          attrsToRemove.push('class')
        }
      }
    })
    
    attrsToRemove.forEach(attr => element.removeAttribute(attr))
  })
}

/**
 * 处理所有HTML内容
 * @param html mammoth转换后的HTML字符串
 * @returns 处理后的HTML字符串
 */
/**
 * 清理不应该出现在最终HTML中的元素
 * 移除可能导致解析错误的元素
 */
function removeInvalidElements(doc: Document): void {
  // 移除所有不在任务列表中的 input 元素
  for (const input of doc.querySelectorAll('input')) {
    const htmlInput = input as HTMLInputElement
    // 检查是否在任务列表的 label 中
    const isInTaskItem = htmlInput.closest('li[data-type="taskItem"] label')
    if (!isInTaskItem) {
      // 不在任务项中，移除
      htmlInput.remove()
    }
  }
  
  // 移除所有 script、style、meta、link 等不应该出现的标签
  const invalidTags = ['script', 'style', 'meta', 'link', 'noscript', 'iframe', 'embed', 'object', 'form']
  invalidTags.forEach(tag => {
    doc.querySelectorAll(tag).forEach(el => el.remove())
  })
  
  // 移除所有注释节点
  const walker = doc.createTreeWalker(
    doc.body,
    NodeFilter.SHOW_COMMENT,
    null
  )
  const comments: Comment[] = []
  let node: Node | null
  while ((node = walker.nextNode())) {
    if (node.nodeType === Node.COMMENT_NODE) {
      comments.push(node as Comment)
    }
  }
  comments.forEach(comment => comment.remove())
}

/**
 * 最终验证和修复
 * 确保HTML结构完全符合Tiptap schema
 */
function finalValidation(doc: Document): void {
  // 移除所有空的任务列表项
  for (const li of doc.querySelectorAll('li[data-type="taskItem"]')) {
    const htmlLi = li as HTMLElement
    // 如果任务项为空，移除复选框相关内容，转换为普通列表项
    if (!htmlLi.textContent?.trim() && htmlLi.querySelector('input[type="checkbox"]')) {
      const input = htmlLi.querySelector('input[type="checkbox"]')
      input?.remove()
      // 移除任务项属性
      htmlLi.removeAttribute('data-type')
      htmlLi.removeAttribute('data-checked')
    }
  }
  
  // 移除空的taskList标记（如果没有有效的taskItem）
  for (const ul of doc.querySelectorAll('ul[data-type="taskList"]')) {
    const hasValidTaskItem = Array.from(ul.querySelectorAll('li[data-type="taskItem"]'))
      .some(li => (li as HTMLElement).textContent?.trim())
    if (!hasValidTaskItem) {
      ul.removeAttribute('data-type')
      ul.classList.remove('task-list')
    }
  }
  
  // 移除所有无效的批注标记（没有commentId的）
  for (const span of doc.querySelectorAll('span.comment-mark')) {
    const htmlSpan = span as HTMLElement
    if (!htmlSpan.getAttribute('data-comment-id')) {
      // 移除批注标记，保留内容
      const fragment = doc.createDocumentFragment()
      while (htmlSpan.firstChild) {
        fragment.appendChild(htmlSpan.firstChild)
      }
      htmlSpan.replaceWith(fragment)
    }
  }
  
  // 移除所有无效的节点类型（不符合Tiptap schema的）
  // 检查所有可能的无效嵌套
  const invalidNestings = [
    // 块级元素不能嵌套在行内元素中
    { selector: 'span p, span div, span h1, span h2, span h3, span h4, span h5, span h6', action: 'unwrap' },
    // 表格不能嵌套
    { selector: 'table table', action: 'convert' },
    // 列表不能直接包含块级元素（除了嵌套列表和段落）
    { selector: 'li > div:not([data-type]), li > h1, li > h2, li > h3, li > h4, li > h5, li > h6, li > blockquote, li > pre, li > table', action: 'wrap' },
  ]
  
  invalidNestings.forEach(({ selector, action }) => {
    doc.querySelectorAll(selector).forEach(element => {
      const htmlEl = element as HTMLElement
      if (action === 'unwrap') {
        // 移除外层包装
        const fragment = doc.createDocumentFragment()
        while (htmlEl.firstChild) {
          fragment.appendChild(htmlEl.firstChild)
        }
        htmlEl.replaceWith(fragment)
      } else if (action === 'convert') {
        // 转换为段落
        const p = doc.createElement('p')
        p.innerHTML = htmlEl.innerHTML
        htmlEl.replaceWith(p)
      } else if (action === 'wrap') {
        // 包装在段落中
        const p = doc.createElement('p')
        htmlEl.parentNode?.insertBefore(p, htmlEl)
        p.appendChild(htmlEl)
      }
    })
  })
  
  // 确保body内至少有一个块级元素
  if (!doc.body.querySelector('p, h1, h2, h3, h4, h5, h6, ul, ol, blockquote, pre, table, hr, div[data-type="page-break"], div[data-type="toc"]')) {
    const p = doc.createElement('p')
    doc.body.appendChild(p)
  }
}

export function processWordHtml(html: string): string {
  const domparser = new DOMParser()
  const doc = domparser.parseFromString(html, 'text/html')
  
  // 调试：打印处理前的HTML结构（前500字符）
  console.log('----------------处理前HTML（前500字符）----------------')
  console.log(html.substring(0, 500))
  console.log('----------------处理前HTML----------------')
  
  // 按顺序执行所有处理函数
  processWordStyleClasses(doc) // 首先处理Word样式类名映射
  processImages(doc)
  processHeadings(doc)
  processParagraphAlignmentAndIndent(doc) // 处理段落对齐和缩进
  processLists(doc)
  processCodeBlocks(doc)
  processTables(doc)
  processBlockquotes(doc)
  processTextStyles(doc)
  processSpecialCharacters(doc) // 处理特殊字符（非断空格等）
  processPageBreaks(doc) // 处理分页符
  processTableOfContents(doc) // 处理目录（在分页符之后，因为目录可能包含分页符）
  removeEmptyParagraphs(doc)
  validateNodeStructure(doc) // 验证节点结构
  removeInvalidElements(doc) // 移除无效元素
  sanitizeHtml(doc) // 清理不支持的标签和属性
  finalValidation(doc) // 最终验证和修复
  
  const processedHtml = doc.body.innerHTML.toString()
  
  // 调试：打印处理后的HTML结构（前500字符）
  console.log('----------------处理后HTML（前500字符）----------------')
  console.log(processedHtml.substring(0, 500))
  console.log('----------------处理后HTML----------------')
  
  return processedHtml
}

